import {
  useRef,
  type SetStateAction,
} from 'react'
import { useUpdate } from '@/library/hooks/use-update'
import { useMemoizedFn } from '@/library/hooks/use-memoized-fn'

type Options<T> = {
  value?: T
  defaultValue: T
  onChange?: (v: T) => void
}

export const usePropsValue = <T>(options: Options<T>): [T, (this: any, v: SetStateAction<T>, forceTrigger?: any) => void] => {
  const { value, defaultValue, onChange } = options

  const update = useUpdate()

  const stateRef = useRef<T>(value !== undefined ? value : defaultValue)

  if (value !== undefined) { // Controlled Component
    stateRef.current = value
  }

  const setState = useMemoizedFn(
    (v: SetStateAction<T>, forceTrigger = false) => {
      // `forceTrigger` means trigger `onChange` even if `v` is the same as `stateRef.current`
      const nextValue = typeof v === 'function'
        ? (v as (prevState: T) => T)(stateRef.current)
        : v
      if (!forceTrigger && nextValue === stateRef.current) return
      stateRef.current = nextValue
      update()
      return onChange?.(nextValue)
    },
  )

  return [stateRef.current, setState] as const
}
